package com.dongbao.action;

import cn.hutool.core.collection.ListUtil;
import com.dongbao.core.config.MyState;
import com.dongbao.core.export.ExportExcelTitle;
import com.dongbao.core.export.ExportExcelUtil;
import com.dongbao.core.export.bean.ExportExcelTheme;
import com.dongbao.core.export.bean.ExportTableBean;
import com.dongbao.entity.AwardedInfo;
import com.dongbao.entity.CacheModule;
import com.dongbao.entity.CodeScoreInfo;
import com.dongbao.service.CodeGradeBiz;
import com.dongbao.util.BeanKit;
import com.dongbao.util.KryoUtil;
import com.intellij.ide.util.frameworkSupport.AddFrameworkSupportDialog;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.impl.file.PsiJavaDirectoryImpl;
import com.intellij.psi.impl.source.PsiJavaFileImpl;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiClassUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ui.ListUiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import java.util.List;

public class DHGModuleAllAction extends AnAction {

    private static final Logger LOGGER = Logger.getInstance(DHGModuleAllAction.class);

    List<AwardedInfo> deductions = Collections.synchronizedList(new ArrayList());

    private final CodeGradeBiz codeGradeBiz = new CodeGradeBiz();

    /**
     * 不需要扫描的包
     * */
    public List<String> excludePackage = new ArrayList<String>(){};

    /**
     * 不需要扫描的包类
     * */
    public List<String> excludeClass = new ArrayList<String>();

    public DHGModuleAllAction(){
        excludePackage.add("com.dongbao.report.core.dsl");

    }

    @Override
    public void actionPerformed(AnActionEvent e) {
        deductions.clear();
        ProgressManager.getInstance().run(new Task.Backgroundable(e.getProject(), e.getPresentation().getText(), false) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                ApplicationManager.getApplication().runReadAction(
                        () -> {
                            runDetection(e,indicator);
                        }
                );
            }
        });

    }

    /**
     * 执行检测入口
     * */
    public void runDetection(AnActionEvent e,ProgressIndicator indicator){
        /* 读取该模块下面所有的文件 */
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        String moduleRootPath = ((PsiJavaDirectoryImpl)e.getData(LangDataKeys.PSI_ELEMENT_ARRAY)[0]).getVirtualFile().getPath();
        VirtualFile parentPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(moduleRootPath, MavenConstants.POM_XML));
        MavenProject project = MavenProjectsManager.getInstance(e.getProject()).findProject(parentPom);
        List<VirtualFile> existingModuleFiles = project.getExistingModuleFiles();

        /* 判断选择的是不是子模块 */
        UUID uuid = UUID.randomUUID();
        String cachePath = MyState.getInstance().getConfig().getCachePath();
        List<String> cacheFiles = new ArrayList<String>();
        if(existingModuleFiles.isEmpty()){
            indicator.setText("处理模块【"+module.getName()+"】");
            /* 根模块 */
            Collection<VirtualFile> moduleJavaFile = FilenameIndex.getAllFilesByExt(e.getProject(), "java", GlobalSearchScope.moduleScope(module));
            runCode(moduleJavaFile,module,indicator,uuid.toString());
            cacheFiles.add(cachePath+"\\"+uuid+"-"+module.getName()+".cache");
        }else{
            /* 遍历所有子模块 */
            for(VirtualFile childModule:existingModuleFiles){
                VirtualFile childPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(childModule.getParent().getPath(), MavenConstants.POM_XML));
                MavenProject childProject = MavenProjectsManager.getInstance(e.getProject()).findProject(childPom);
                Module moduleForFile = ProjectFileIndex.getInstance(e.getProject()).getModuleForFile(childModule.getCanonicalFile());
                indicator.setText("处理模块【"+moduleForFile.getName()+"】");
                Collection<VirtualFile> moduleJavaFile = FilenameIndex.getAllFilesByExt(e.getProject(), "java", GlobalSearchScope.moduleScope(moduleForFile));
                runCode(moduleJavaFile,moduleForFile,indicator,uuid.toString());
                cacheFiles.add(cachePath+"\\"+uuid+"-"+moduleForFile.getName()+".cache");
            }
        }
        /* 统计所有模块的代码得分情况 */
        summaryStatistics(cacheFiles);

    }

    public void summaryStatistics(List<String> cacheFiles){
        /* 遍历去读取缓存中的内容,合并到一个集合中 */
        List<AwardedInfo> curDeductions = new ArrayList<AwardedInfo>();
        for(String cachePath:cacheFiles){
            CacheModule  cacheModule = KryoUtil.readKryo(cachePath);
        }
        System.out.println("66666");
    }

    public void runCode(Collection<VirtualFile> moduleJavaFile,Module moduleForFile,ProgressIndicator indicator,String uuid){
        /* 根据获取的文件列表与模块 执行代码检测 */
//        ThreadPoolExecutor threadPool = DongBaoThreadUtil.getInstance().get("report", 0.8f);
//        List<Future<CopyOnWriteArrayList<AwardedInfo>>> futures = new ArrayList<>();
        CodeGradeBiz codeGradeBiz = new CodeGradeBiz();
        indicator.setText("开始执行【"+moduleForFile.getName()+"】模块文件代码检查，文件总数:"+moduleJavaFile.size());

        /* ==================  普通调用 start  ======================== */
        int num = 0;
        //问题数
        int problemNum = 0;
        List<PsiFile> psiFiles = PsiUtilCore.toPsiFiles(PsiManager.getInstance(moduleForFile.getProject()), moduleJavaFile);
        String cachePath = MyState.getInstance().getConfig().getCachePath();
        for(PsiFile file:psiFiles){
            /* 判断是否在白名单 */
            num++;
            if(excludePackage.contains(((PsiJavaFileImpl) file).getPackageName())){
                continue;
            }
            indicator.setText("当前进度:"+num+"/"+moduleJavaFile.size()+",当前发现问题数【"+problemNum+"】,当前检测文件名称【"+file.getName()+"】");

            CodeScoreInfo codeScoreInfo = new CodeScoreInfo();
            CodeScoreInfo calculate = codeGradeBiz.calculate(file.getVirtualFile(),file, codeScoreInfo,moduleForFile.getProject());
            /* 分析评分并将错误原因弹出 */
            /* 遍历得分情况 进行分数的加减 */
            List<AwardedInfo> curDeductions = codeScoreInfo.getDeduction();
            problemNum+=curDeductions.size();
            deductions.addAll(curDeductions);
        }

        /* 测试导出方法 */
        indicator.setText("正在执行数据导出至Excel");
        exportExcel(deductions,moduleForFile);

        deductions.forEach(item->{
            item.setVirtualFile(null);
        });
        CacheModule cacheModule = new CacheModule();
        cacheModule.setModuleName(moduleForFile.getName());
        cacheModule.setAwardedInfo(deductions);
        /* 错误信息保存到缓存中 待最后汇总的报表时使用 */

        KryoUtil.writeKryo(cachePath,uuid+"-"+moduleForFile.getName()+".cache",cacheModule);

//        System.out.println("666");
        /* 执行导出Excel */


        /* ==================  普通调用 end  ======================== */
        /* ==================  使用线程 start  ======================== */
//        int num = 0;
//        for(VirtualFile file:moduleJavaFile){
//            num++;
//            indicator.setText("当前进度:"+num+"/"+moduleJavaFile.size());
//            Future<CopyOnWriteArrayList<AwardedInfo>> future = threadPool.submit(new CodeInspectRunnable(file, moduleForFile, codeGradeBiz,moduleForFile.getProject()));
//            futures.add(future);
//        }
//
//        CopyOnWriteArrayList<AwardedInfo> listData = new CopyOnWriteArrayList<>();
//        indicator.setText("开始执行【"+moduleForFile.getName()+"】模块文件代码检查完成开始合并错误信息");
//        for (Future<CopyOnWriteArrayList<AwardedInfo>> future : futures) {
//            try {
//                CopyOnWriteArrayList<AwardedInfo> awardedInfos = future.get();
//                listData.addAll(awardedInfos);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            } catch (ExecutionException e) {
//                e.printStackTrace();
//            }
//        }
//        indicator.setText("开始执行【"+moduleForFile.getName()+"】模块文件错误信息导出操作");
//        System.out.println("666");
        /* ==================  使用线程 end  ======================== */

    }

    public void exportExcel(List<AwardedInfo> deductions,Module module){
        try{
            /* 打开弹窗让选择保存路径 */
            String fileName = "检测问题导出-"+module.getName()+"["+UUID.randomUUID().toString()+"]"+".xlsx";
            File exportFile=new File(MyState.getInstance().getConfig().getCachePath()+"\\"+fileName);
            FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
            ExportTableBean tableBean = new ExportTableBean();
            tableBean.setTitle("检测问题导出");
            tableBean.setHeaders(Arrays.asList("问题等级","问题编号","文件名","类名","方法名","问题名称","详情","代码行"));
            tableBean.setKeys(Arrays.asList("level","code","fileName","javaClass","javaMethod","rule","describe","beginline"));
            List<Map<String, Object>> maps = BeanKit.EntityConvertMap(deductions);
            tableBean.setDataList(maps);
            tableBean.setWidth(Arrays.asList(20,20,20,20,20,20,20,20));
            ExportExcelUtil.exportExcel(tableBean, "问题详细列表", "123456", fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();

            Desktop.getDesktop().open(exportFile);
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    @Override
    public void update(@NotNull final AnActionEvent e) {
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        try{
            boolean enable = module != null && AddFrameworkSupportDialog.isAvailable(module);
            if (ActionPlaces.isPopupPlace(e.getPlace())) {
                e.getPresentation().setVisible(enable);
            }
            else {
                e.getPresentation().setEnabled(enable);
            }
        }catch (Exception exce){
            e.getPresentation().setEnabled(true);
        }
    }
}
